package com.artup.service.impl;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.artup.pojo.ImageEntity;
import com.artup.pojo.MaterialEdit;
import com.artup.pojo.TextEdit;
import com.artup.service.Command;
import com.artup.util.ClassUtil;
import com.artup.util.CommonUtils;
import com.artup.util.math.MathUtil;
import com.artup.util.pdf.PdfUtil;
import com.artup.util.pdf.PdfUtil.PdfParam;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.Barcode128;
import com.itextpdf.text.pdf.BarcodePDF417;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfRectangle;
import com.itextpdf.text.pdf.PdfWriter;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Setter
@Getter
@Service( value = "pdfCommond" )
public abstract class PdfCreatorCommand implements Command<PdfUtil.PdfParam, String> {
	
	/**
	 * 出血线与裁切框间距3mm
	 */
	public static final int BLEED_SPACE = 3;
	
	/**
	 * pdf页面边与裁切框间距15mm
	 */
	public static final int PDF_PAGE_SPACE = 15;
	
	/**
	 * 脚线长度5mm
	 */
	public static final int FOOT_LINE_LENGTH = 5;
	
	/**
	 * 订单信息框高度为5mm
	 */
	public static final int ORDER_HEIGHT = 5;
	
	/**
	 * 条形码框宽25mm
	 */
	public static final int BARCODE_WIDTH = 25;
	
	/**
	 * 条形码框高8mm
	 */
	public static final int BARCODE_HEIGHT = 8;
	
	/**
	 * pdf模板编码
	 */
	protected String code;
	
	/**
	 * pdf模板名称
	 */
	protected String name;
	
	/**
	 * 裁切框(成品框)宽
	 */
	protected Float cropWidth; 
	
	/**
	 * 裁切框(成品框)高
	 */
	protected Float cropHeight; 
	
	/**
	 * 画芯图片框宽
	 */
	protected Float picWidth; 
	
	/**
	 * 画芯图片框高
	 */
	protected Float picHeight; 
	 
//	protected Cache envCache = MarsEnvironment.getEnvironment().getCache();
	
	/**
	 * 计算pdf页面大小
	 * @return
	 */
	protected abstract Rectangle getPdfBoxRectangle();

	@Override
	public void execute(PdfParam param, List<MaterialEdit> materialEditList) throws Exception {
		log.info("param = {}", JSONObject.toJSONString(param));
		
		//设置pdf页面大小
		param.setRectangle(getPdfBoxRectangle());
		
		param.setDocumentBuilder(new PdfUtil.PdfDocumentBuilder(){
			@Override
			public void beforeOpen(Document doc, PdfParam param) throws Exception {
				beforeOpenDocument(doc, param);
			}
			
			@Override
			public void postOpen(PdfWriter writer, Document document, PdfParam param) throws Exception {
				log.info("<<<  ---------------------------- 开始添加内容 --------------------------------------------");
				
				//设置pdf内容
				doBuildContent(writer, document, materialEditList);
				
				log.info("---------------------------- 添加内容完成 -------------------------------------------- >>>");
			}
		});
		
		
		PdfUtil.buildPdf(null, param);
	}
	
	/**
	 * 设置pdf内容
	 * 
	 * @param writer
	 * @param document
	 * @param param
	 * @throws Exception
	 */
	private void doBuildContent(PdfWriter writer, Document document, List<MaterialEdit> materialEditList)throws Exception{
		try{
			if(CommonUtils.isNotEmpty(materialEditList)){
				for(MaterialEdit materialEdit : materialEditList){
					if(!document.newPage()){
						log.error("创建 PDF 新页面失败！");
						
						continue;
					}
					
					//设置pdf内容
					buildContent(writer, document, materialEdit);
					
					//设置出血框
					setBleedBox(writer, document);
					
					//设置成品(裁切)框
					setArtBox(writer,  document);
					
					//设置脚线
					setFootLine(writer, document);
				}
				
				//内容创建完成后进行清理工作
				this.afterContentBuild(writer, document);
				
				writer.setViewerPreferences(PdfWriter.PageModeUseThumbs);
			}
		}catch(Exception e){
			log.error(e.getMessage(), e);
			throw new Exception(e.getMessage());
		}
	}
	
	/**
	 * 内容创建完成后进行清理工作
	 * 
	 * @param writer
	 * @param document
	 * @param param
	 */
	private void afterContentBuild(PdfWriter writer, Document document){
		
	}
	
	/**
	 * 打开document之前回调函数，可设置一些pdf属性
	 * 
	 * @param doc
	 * @param param
	 */
	protected void beforeOpenDocument(Document doc, PdfParam param){}
	
	/**
	 * 设置pdf内容
	 * 
	 * @param writer Writer
	 * @param document Document
	 * @param param 参数
	 * @param currentPage pdf当前页，从1开始。
	 * @param contentEntity pdf当前页的内容
	 */
	private void buildContent(PdfWriter writer, Document document, MaterialEdit materialEdit)throws Exception{
		addImageContent(document, materialEdit);
	}
	
	private void doInvoke(PdfWriter writer, Document document, List<MaterialEdit> materialEditList, String key){
		String methodName = key + "Builder";//调用方法： editPictureBuilder 或者 editTxtBuilder
		Method method = ClassUtil.findMethodByName(this.getClass(), methodName);
		
		if(method == null){
			log.error("未找到的方法：\"{}\" in class \"{}\" ", methodName, this.getClass().getName());
			
			return;
		}
		
		try{
			method.invoke(this, writer, document, materialEditList);
		}catch(Exception e){
			log.error(e.getMessage());
		}
	}
	
	/**
	 * 添加图片到pdf中
	 * 
	 * @param doc
	 * @param content
	 * @param material
	 * @param currentPage
	 * @param propertyName
	 */
	protected void editPictureBuilder(PdfWriter writer, Document doc, List<MaterialEdit> materialEditList){
		
		for(MaterialEdit materialEdit : materialEditList){
			if(null == materialEdit){
				continue;
			}
			
			//将当前图片添加到pdf内容中
			try {
				addImageContent(doc, materialEdit);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 添加文字内容到pdf中
	 * 
	 * @param doc
	 * @param content
	 * @param editPictures
	 * @param currentPage
	 * @param propertyName
	 */
	private void editTxtBuilder(PdfWriter writer, Document doc, List<TextEdit> textEditList){
		for(TextEdit textEdit : textEditList){
			if(null == textEdit){
				continue;
			}
			
			//将当前文本添加到pdf内容中
			try {
				addTextContent(writer, doc, textEdit);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 添加文字信息
	 * 
	 * fontSize = 8 时，
	 * 	数字字符宽度 ：4.4160004
	 * 	英文字符宽度 ：4.688
	 * 	汉字宽度	： 8.0
	 * 
	 * @param doc
	 * @param editTxt
	 * @param cnf
	 * @throws Exception
	 */
	protected void addTextContent(PdfWriter writer, Document doc, TextEdit editTxt)throws Exception{
		String txtContent = editTxt.getContent();
		if(StringUtils.isBlank(txtContent)){
			log.error("{} No textContent ");
			return;
		}
		txtContent = txtContent.replaceAll("LF", "\\\n");
		float llx = PdfUtil.convertMm2Pt(editTxt.getX())  + PdfUtil.convertMm2Pt(BLEED_SPACE + FOOT_LINE_LENGTH);
		float lly = PdfUtil.convertMm2Pt(editTxt.getY()) + PdfUtil.convertMm2Pt(BLEED_SPACE + FOOT_LINE_LENGTH);
		
		float width = PdfUtil.convertMm2Pt(editTxt.getWidth());
		float height = PdfUtil.convertMm2Pt(editTxt.getHeight());
		
		//右上角坐标
		float rux = llx + width;
		float ruy = lly + height;
		
		float fontSize = editTxt.getFontSize(); //PdfUtil.convertMm2Pt(cnf.getFontSize());
		String fontName = editTxt.getFontName();
		fontName = StringUtils.isBlank(fontName) ? PdfParam.DEFAULT_FONT : fontName;
		fontName = fontName.startsWith("fonts") ? fontName : "fonts/" + fontName;
		Phrase orderTxt = new Phrase(txtContent, this.getChineseFont(fontName, (int)fontSize));
		
		//行间距
		float maxLeadding = orderTxt.getTotalLeading();
		int align = Element.ALIGN_CENTER;
		
		PdfContentByte content = writer.getDirectContent(); 
		content.beginText();
		
		ColumnText columnTxt = new ColumnText(content);
		 
		columnTxt.setSimpleColumn(orderTxt, llx, lly, rux, ruy, maxLeadding, align);
		
		//文字透明度
		PdfGState gs = new PdfGState();
		gs.setFillOpacity(1f);
		content.setGState(gs);
		
		columnTxt.setInheritGraphicState(true);
		columnTxt.go();
		
		content.endText();
		content.stroke();
		
		log.debug("addTxtContent to document [ \"txtContent\" : \"{}\", \"llx\" : {}pt, \"lly\" : {}pt, \"width\" : {}pt, \"height\" : {}pt ] ", txtContent, llx, lly, width, height);
	}
	
	private void addImageContent(Document doc, MaterialEdit materialEdit) throws Exception{
		if(null == materialEdit) {
			log.warn("无参数！");
			
			return;
		}
		if(StringUtils.isBlank(materialEdit.getEditedMaterialPath())){
			log.warn("无编辑的素材图片！");
			
			return;
		}
		
		//图片
		Image img = Image.getInstance(materialEdit.getEditedMaterialPath());
		
		//图片框宽
		float width = PdfUtil.convertMm2Pt(materialEdit.getWidth());
				
		//图片框高
		float height = PdfUtil.convertMm2Pt(materialEdit.getHeight());
		
		double wwidth = MathUtil.multiply(ImageEntity.MM2PX_150, materialEdit.getWidth());
		double hheight = MathUtil.multiply(ImageEntity.MM2PX_150, materialEdit.getHeight());
		
		log.debug("图片的宽 : {}pt, 图片的高 : {}pt, 图片框150dpi时最小宽 : {}pt, 图片框150dpi时最小高 : {}pt ", img.getWidth(), img.getHeight(), wwidth, hheight);

		float llx = PdfUtil.convertMm2Pt(materialEdit.getX()) + PdfUtil.convertMm2Pt(BLEED_SPACE + FOOT_LINE_LENGTH);
		float lly = PdfUtil.convertMm2Pt(materialEdit.getY()) + PdfUtil.convertMm2Pt(BLEED_SPACE + FOOT_LINE_LENGTH);
		img.setAbsolutePosition(llx, lly);
		
		log.debug("添加图片到 PDF 页面中 [ \"image\" : \"{}\", \"llx\" : {}pt, \"lly\" : {}pt, \"width\" : {}pt, \"height\" : {}pt ] ", materialEdit.getEditedMaterialPath(), llx, lly, width, height);
		
		img.scaleAbsolute(width, height);
		doc.add(img);
	}
	
//	private void addImageContent(Document doc, String imagePath, int currentPage)throws Exception{
//		//图片路径
//		if(StringUtils.isBlank(imagePath)){
//			log.warn("{} No image Found. \"srcImagePath\" is null. ", Mars.LOG_PRE);
//			return;
//		}
//		
//		//图片
//		Image img = Image.getInstance(imagePath);
//		
//		//图片框宽
//		float width = PdfUtil.convertMm2Pt(this.getPicWidth());
//		
//		//图片框高
//		float height = PdfUtil.convertMm2Pt(this.getPicHeight());
//		
//		Rectangle pdfBox = doc.getPageSize();
//		float llx = (pdfBox.getWidth() - width) / 2;
//		float lly = (pdfBox.getHeight() - height) / 2;
//		
//		img.setAbsolutePosition(llx, lly);
//		img.scaleAbsolute(width, height);
//		doc.add(img);
//		
//		log.debug("{} add picture to document [ currentPage : {}, llx : {} pt, lly : {} pt, width : {} pt, height : {} pt ]", Mars.LOG_PRE, currentPage, llx, lly, width, height);
//	}
	
	/**
	 * 默认中文字体，微软雅黑
	 * @param fontSize
	 * @return
	 * @throws IOException
	 * @throws DocumentException
	 */
	protected Font getDefaultChineseFont(int fontSize)throws IOException,DocumentException{
		return this.getChineseFont(PdfParam.DEFAULT_FONT, fontSize);
	}
	
	protected Font getChineseFont(String fontName, int fontSize)throws IOException,DocumentException{
		fontName = StringUtils.isBlank(fontName) ? PdfParam.DEFAULT_FONT : fontName;
		BaseFont bfChinese = BaseFont.createFont(fontName, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
		bfChinese = BaseFont.createFont(PdfUtil.PdfParam.DEFAULT_FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
	    Font fontChinese = new Font(bfChinese, fontSize, Font.NORMAL);
	    return fontChinese;
	}
	
	/**
	 * 生成条形码
	 * 
	 * @param content
	 * @param barCodeInfo
	 * @param width
	 * @param height
	 * @param encode
	 * @param format
	 * @return
	 * @throws Exception
	 */
	protected Image generateBarCode128(PdfContentByte content, String barCodeInfo)throws Exception{
		if (StringUtils.isBlank(barCodeInfo)) {
			throw new Exception("条形码的文本信息参数不能为空！");
		}
		com.itextpdf.text.pdf.Barcode128 barcodePDF = new com.itextpdf.text.pdf.Barcode128();
		barcodePDF.setCode(barCodeInfo);
		barcodePDF.setCodeType(Barcode128.CODE128);
		//barcodePDF.setFont(null);
		barcodePDF.setChecksumText(false);
		barcodePDF.setGenerateChecksum(false);
		return barcodePDF.createImageWithBarcode(content, BaseColor.BLACK, BaseColor.BLACK);
	}
	
	/**
	 * 
	 * @param barCodeInfo
	 * @return
	 * @throws Exception
	 */
	public byte[] generateBarCode417(String barCodeInfo)throws Exception{
		int width = (int)PdfUtil.convertMm2Pt(BARCODE_WIDTH);
		int height = (int)PdfUtil.convertMm2Pt(BARCODE_HEIGHT);
		return generateBarCode417(barCodeInfo, width, height, "UTF-8", "jpg");
	}
	
	/**
	 * 
	 * @param barCodeInfo
	 * @param encode
	 * @param format
	 * @return
	 * @throws Exception
	 */
	protected byte[] generateBarCode417(String barCodeInfo, int width, int height, String encode, String format)throws Exception{
		if (StringUtils.isBlank(barCodeInfo)) {
			throw new Exception("条形码的文本信息参数不能为空！");
		} 
		 
		BarcodePDF417 barcodePDF = new BarcodePDF417();
		barcodePDF.setText(barCodeInfo.getBytes(encode));
		java.awt.Image pdfImg = barcodePDF.createAwtImage(Color.black, Color.white);
		BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		java.awt.Graphics g = img.getGraphics();
		g.drawImage(pdfImg, 0, 0, Color.white, null);
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		try{
			ImageIO.write(img, format, os);
			return os.toByteArray();
		}catch(Exception e){
			log.error(e.getMessage(), e);
			throw new Exception(e.getMessage());
		}finally{
			if(os != null){
				os.close();
			}
		}
	}
	
//	protected byte[] generateBarCodeJpgByZxing(String barCodeInfo)throws Exception{
//		int width = (int)PdfUtil.convertMm2Pt(BARCODE_WIDTH);
//		int height = (int)PdfUtil.convertMm2Pt(BARCODE_HEIGHT);
//		return generateBarCodeJpgByZxing(barCodeInfo, width, height, "UTF-8", "jpg");
//	}
	
//	/**
//	 * 使用zxing库生成条形码
//	 * 
//	 * @param barCodeInfo
//	 * @param width
//	 * @param height
//	 * @param encode
//	 * @param format
//	 * @return
//	 * @throws Exception
//	 */
//	protected byte[] generateBarCodeJpgByZxing(String barCodeInfo, int width, int height, String encode, String format)throws Exception{
//		if (StringUtils.isBlank(barCodeInfo)) {
//			throw new Exception("条形码的文本信息参数不能为空！");
//		}
//		
//		ByteArrayOutputStream os = null;
//		try{
//			// 文字编码  
//	        Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();  
//	        hints.put(EncodeHintType.CHARACTER_SET, encode);
//	        BitMatrix bitMatrix = new MultiFormatWriter().encode(barCodeInfo, BarcodeFormat.CODE_128, height, height, hints);  
//	        
//	        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//	        os = new ByteArrayOutputStream();
//	        for (int x = 0; x < width; x++){  
//	            for (int y = 0; y < height; y++){  
//	            	img.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE);  
//	            }  
//	        }  
//	        ImageIO.write(img, format, os);
//			return os.toByteArray();
//		}catch(Exception e){
//			log.error(e.getMessage(), e);
//			throw new Exception(e.getMessage());
//		}finally{
//			if(os != null){
//				os.close();
//			}
//		}
//		 
//	}
	
	/**
	 * 根据用户的操作对原图进行操作
	 * 
	 * @param actions
	 * @param pdfParam
	 */
//	protected void doExecuteInterceptor(Document doc, PdfParam param, PdfContentEntity content, int currentPage){
//		//操作 
//		Collection<Action> actions = content.getActions();
//		
//		if(actions == null || actions.isEmpty()){
//			log.warn("{} No action for building pdf ", Mars.LOG_PRE);
//			return;
//		}
//		
////		InterceptorHandlerChain<PdfContentEntity, String> chain = new DefaultInterceptorHandlerChain<PdfContentEntity, String>();
////		for(Action action : actions){
////			String actionCode = action.getCode();
////			if(StringUtils.isBlank(actionCode)){
////				continue;
////			}
////			
////			InterceptorHandler<PdfContentEntity, String> inter = SpringContextHolder.getBean(actionCode + "InterceptorHandler");
////			chain.addLast(actionCode, inter);
////		}
//		
//		InterceptorExecutor.doExecuteWithContextName("pdfCreatorInterceptorContext", content);//.doExecute(chain, content);
//	}
	
	/**
	 * 设置出血框
	 * @param writer
	 * @param document
	 * @param param
	 */
	protected void setBleedBox(PdfWriter writer, Document document){
		Rectangle bleedBox = this.getBleedBox(document);
		PdfRectangle pdfBleedBox = new PdfRectangle(bleedBox.getLeft(), bleedBox.getBottom(),bleedBox.getRight(), bleedBox.getTop());
		writer.getPageDictEntries().put(PdfName.BLEEDBOX, pdfBleedBox);
		log.debug("add bleedBox [ width : {} pt, height : {} pt ] ", pdfBleedBox.width(), pdfBleedBox.height());
	}
	
	/**
	 * 设置裁切(成品)框
	 * 
	 * @param writer
	 * @param document
	 * @param param
	 * @param curPage
	 */
	protected void setArtBox(PdfWriter writer, Document document){
		Rectangle artBox = getArtBox(document);		
		PdfRectangle pdfArtBox = new PdfRectangle(artBox.getLeft(), artBox.getBottom(),artBox.getRight(), artBox.getTop());
		
		//成品框
		writer.getPageDictEntries().put(PdfName.ARTBOX, pdfArtBox);
		
		//裁切框
		writer.getPageDictEntries().put(PdfName.TRIMBOX, pdfArtBox);
		
		log.debug("add TrimBox [ width : {} pt, height : {} pt ] ", pdfArtBox.width(), pdfArtBox.height());
	}
	
	/**
	 * 设置脚线
	 * 
	 * @param writer
	 * @param document
	 * @param param
	 */
	protected void setFootLine(PdfWriter writer, Document document){
		PdfContentByte content = writer.getDirectContent();

		//脚线长
		float footLine = PdfUtil.convertMm2Pt(FOOT_LINE_LENGTH);
		
		//出血框
		Rectangle bleedBox = this.getBleedBox(document);
		float bleedWidth = bleedBox.getWidth();
		float bleedHeight = bleedBox.getHeight();
		
		//pdf页面大小
		Rectangle pdfBox = document.getPageSize();
		float pdfWidth = pdfBox.getWidth();
		float pdfHeight = pdfBox.getHeight();
		
		//左下角x方向上脚线起点
		float llxX = (pdfWidth - bleedWidth) / 2 - footLine;
		float llyX = (pdfHeight - PdfUtil.convertMm2Pt(this.getCropHeight())) / 2;
		content.moveTo(llxX, llyX);
		content.lineTo(llxX + footLine, llyX);
		
		//右下角x方向上脚线起点
		float rlxX = pdfWidth - (pdfWidth - bleedWidth) / 2;
		float rlyX = llyX;
		content.moveTo(rlxX, rlyX);
		content.lineTo(rlxX + footLine, rlyX);
				
		//左上角x方向上脚线起点
		float luxX = llxX;
		float luyX = pdfHeight - (pdfHeight - PdfUtil.convertMm2Pt(this.getCropHeight())) / 2;
		content.moveTo(luxX, luyX);
		content.lineTo(luxX + footLine, luyX);
		
		//右上角x方向上脚线起点
		float ruxX = rlxX; 
		float ruyX = luyX;
		content.moveTo(ruxX, ruyX);
		content.lineTo(ruxX + footLine, ruyX);
		
		//左下角y方向上脚线起点
		float llxY = (pdfWidth - PdfUtil.convertMm2Pt(this.getCropWidth())) / 2;
		float llyY = (pdfHeight - bleedHeight) / 2 - footLine;
		content.moveTo(llxY, llyY);
		content.lineTo(llxY, llyY + footLine);
		
		//左上角y方向上脚线起点
		float luxY = llxY;
		float luyY = pdfHeight - (pdfHeight - bleedHeight) / 2;
		content.moveTo(luxY, luyY);
		content.lineTo(luxY, luyY + footLine);
		
		//右下角y方向上脚线起点
		float rlxY = pdfWidth - (pdfWidth - PdfUtil.convertMm2Pt(this.getCropWidth())) / 2;
		float rlyY = llyY;
		content.moveTo(rlxY, rlyY);
		content.lineTo(rlxY, rlyY + footLine);
		
		//右上角y方向上脚线起点
		float ruxY = rlxY;
		float ruyY = pdfHeight - (pdfHeight - bleedHeight) / 2;
		content.moveTo(ruxY, ruyY);
		content.lineTo(ruxY, ruyY + footLine);
		
		content.stroke();
		
		log.debug("设置脚线 - 完成。");
	}
	
	/**
	 * 出血框
	 * @param document
	 * @return
	 */
	protected Rectangle getBleedBox(Document document){
		//出血框宽单位mm
		float bleedWidth = this.getCropWidth() + 2 * BLEED_SPACE;
		float bleedHeight = this.getCropHeight() + 2 * BLEED_SPACE;
		//出血框宽单位pt
		float bleedWidthPt = PdfUtil.convertMm2Pt(bleedWidth);
		float bleedHeightPt = PdfUtil.convertMm2Pt(bleedHeight);
		Rectangle pdfBox = document.getPageSize();
		float llx = (pdfBox.getWidth() - bleedWidthPt) / 2;
		float lly = (pdfBox.getHeight() - bleedHeightPt) / 2;
		
		Rectangle bleedBox = new Rectangle(llx, lly, llx + bleedWidthPt, lly + bleedHeightPt);
		return bleedBox;
	}
	
	/**
	 * 成品框
	 * 
	 * @param document
	 * @return
	 */
	protected Rectangle getArtBox(Document document){
		//出血框宽单位pt
		float artWidthPt = PdfUtil.convertMm2Pt(this.getCropWidth());
		float artHeightPt = PdfUtil.convertMm2Pt(this.getCropHeight());
		Rectangle pdfBox = document.getPageSize();
		float llx = (pdfBox.getWidth() - artWidthPt) / 2;
		float lly = (pdfBox.getHeight() - artHeightPt) / 2;
		
		return new Rectangle(llx, lly, llx + artWidthPt, lly + artHeightPt);
	}
	
	/**
	 * 在指定位置增加增加条形码
	 * 
	 * @param document
	 * @param llx
	 * @param lly
	 * @param barCode
	 */
	protected void addBarCode128Content(PdfWriter writer, Document document, float llx, float lly, int align, String barCode){
		try{
			log.debug("添加条形码，\"{}\" at [ {},{} ] align : {} ", barCode, llx, lly, align);
			
			int width = (int)PdfUtil.convertMm2Pt(BARCODE_WIDTH);
			int height = (int)PdfUtil.convertMm2Pt(BARCODE_HEIGHT);
			
			com.itextpdf.text.Image img = generateBarCode128(writer.getDirectContent(), barCode); 
			img.setAlignment(align);
			img.setAbsolutePosition(llx, lly);
			img.scaleAbsolute(width, height);
			document.add(img);
		}catch(Exception e){
			log.error(e.getMessage(), e);
		}
	}
	
	/**
	 * 在指定位置宽高矩形内增加文本内容
	 * 
	 * @param writer
	 * @param llx 左下角x坐标
	 * @param lly 左下角y坐标
	 * @param width 宽
	 * @param height 高
	 * @param txtContent 文字内容
	 * @param fontSize 字体大小
	 * @param align 对齐方式 0:左对齐； 1：居中对齐； 2：右对齐
	 * 
	 * @throws Exception
	 */
	protected void addTextContent(PdfWriter writer, float llx, float lly, float width, float height, String txtContent, int fontSize, int align)throws Exception{
		PdfContentByte content = writer.getDirectContent();
		
		if(StringUtils.isNotBlank(txtContent)){
			txtContent = txtContent.replaceAll("LF", "\\\n");
		}
		content.beginText();
		ColumnText columnTxt = new ColumnText(content);
		Phrase orderTxt = new Phrase(txtContent, this.getDefaultChineseFont((int)fontSize));
//		//右上角坐标
		float rux = llx + width;
		float ruy = lly + height;
		
		//log.debug("{} add txtContent \"{}\" at [ {},{} {},{} ] ", Mars.LOG_PRE, txtContent, llx, lly, rux, ruy);
		
		columnTxt.setSimpleColumn(orderTxt, llx, lly, rux, ruy, 16, align);
		
		//文字透明度
		PdfGState gs = new PdfGState();
		gs.setFillOpacity(1f);
		content.setGState(gs);
		
		columnTxt.setInheritGraphicState(true);
		columnTxt.go();
		
		content.endText();
		content.stroke();
	}
}
